#include <vulkan/vulkan.h>  // 包含vulkan sdk头文件
#include <GLFW/glfw3.h>
#include <stdexcept>
#include <iostream>

class draw_triangle_app {
public:
    void run() {
        init_window();
        init_vulkan();
        loop();
        cleanup();
    }
private:
    void init_window();
    void init_vulkan();
    void loop();
    void cleanup();

    void create_instance();
private:
    GLFWwindow * m_window {nullptr};
    VkInstance   m_instance;        // vulkan实例
};


const uint32_t WIN_WIDTH = 800;
const uint32_t WIN_HEIGHT = 600;

void draw_triangle_app::init_window() {
    glfwInit();     //  initializes the GLFW library.
    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);   // glfw最初为OpenGL设计，这里用于告诉glfw创建窗口时，不要创建opengl context
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);     // 告诉glfw创建窗口时，不允许改变窗口大小

    // 创建窗口
    m_window = glfwCreateWindow(WIN_WIDTH, WIN_HEIGHT, "Vulkan", nullptr, nullptr);
}

// 创建实例以初始化vulkan库，该实例是应用与vulkan库的连接，同时将一些应用信息告知驱动
void draw_triangle_app::init_vulkan() {
    create_instance();
}

void draw_triangle_app::create_instance() {
    // 当前应用相关信息
    VkApplicationInfo app_info{};
    app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;    // 当前结构类型ID，即VkApplicationInfo
    app_info.pApplicationName = "Hello Triangle";
    app_info.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
    app_info.pEngineName = "No Engine";
    app_info.engineVersion = VK_MAKE_VERSION(1, 0, 0);
    app_info.apiVersion = VK_API_VERSION_1_0;

    // 获取glfw扩展
    uint32_t glfw_extensions_count = 0;
    const char** glfw_extensions;
    glfw_extensions = glfwGetRequiredInstanceExtensions(&glfw_extensions_count);

    // 实例创建信息
    VkInstanceCreateInfo create_info{};
    create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
    create_info.pApplicationInfo = &app_info;
    create_info.enabledExtensionCount = glfw_extensions_count;
    create_info.ppEnabledExtensionNames = glfw_extensions;
    create_info.enabledLayerCount = 0;

    // 创建vulkan实例
    VkResult r1 = vkCreateInstance(&create_info, nullptr, &m_instance);
    if ( r1 != VK_SUCCESS) throw std::runtime_error("failed to create instance");

}

void draw_triangle_app::loop() {
    // 执行窗口事件循环直到窗口退出
    while (!glfwWindowShouldClose(m_window)) {
        glfwPollEvents(); 
    }
}

void draw_triangle_app::cleanup() {
    vkDestroyInstance(m_instance, nullptr);
    glfwDestroyWindow(m_window);
    glfwTerminate();
}


int main(int argc, char **argv) {
    draw_triangle_app app;
    try {
        app.run();
    } catch (const std::exception & e) {
        std::cerr<<e.what()<<std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}




